#!/usr/bin/python3
# -*- coding: utf-8 -*-

"""
检测应用，把边界图形标记出来.

author: Xie Junming
Last edited: 2022/11/07
"""

import cv2
import numpy as np


class Detection(object):
    """
    输出图片或图片的地址，输出絮凝的 数量:int, 面积:np.ndarray
    """

    def __init__(self):
        self.input_object = 0
        self.floc_num = 0
        self.floc_area = np.array([])
        self.approx_list = []  # 获取轮廓角点坐标
        self.img_gray = 0
        self.img_rgb = 0
        self.contours = 0
        self.constant = 0

    def read_img(self, input_object: str or np.ndarray):
        self.input_object = input_object
        if isinstance(self.input_object, str):
            self.img_gray = cv2.imread(self.input_object, 0)
            self.img_rgb = cv2.imread(self.input_object, 3)

        elif isinstance(self.input_object, np.ndarray):
            if len(self.input_object.shape) == 2:
                # 为单通道照片
                self.img_gray = self.input_object
                self.img_rgb = cv2.cvtColor(self.img_gray, cv2.COLOR_RGB2GRAY)
            elif len(self.input_object.shape) == 3:
                # 为3通道照片
                self.img_gray = cv2.cvtColor(self.input_object, cv2.COLOR_GRAY2BGR)
                self.img_rgb = self.input_object

    # 定义形状检测函数
    def ShapeDetection(self, img):
        real_contours = []
        self.contours, hierarchy = cv2.findContours(img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)  # 寻找轮廓点
        floc_area = []
        for obj in self.contours:
            area = cv2.contourArea(obj)  # 计算轮廓内区域的面积
            # print(area)
            # if area < 10:
            #     continue
            real_contours.append(obj)
            perimeter = cv2.arcLength(obj, True)  # 计算轮廓周长
            approx = cv2.approxPolyDP(obj, 0.02 * perimeter, True)  # 获取轮廓角点坐标
            self.approx_list.append(approx)
            floc_area.append(area)
        self.contours = real_contours
        self.floc_area = np.array(floc_area)
        # self.savefig("./test_output.png")
        return True

    def show_fig(self):
        # cv2.drawContours(imgContour, obj, -1, (255, 0, 0), 4)  # 绘制轮廓线
        for obj in self.contours:
            cv2.drawContours(self.img_rgb, obj, -1, (160, 32, 240), 1)  # 绘制轮廓线
        area_sum = sum(self.floc_area)
        num = len(self.floc_area)
        self.constant = cv2.copyMakeBorder(
            self.img_rgb, 100, 100, 100, 100, cv2.BORDER_CONSTANT, value=[255, 255, 255])
        cv2.putText(self.constant, "per area=%.2f" % (area_sum / num), (30, 30), cv2.FONT_HERSHEY_COMPLEX, 0.6,
                    (0, 191, 255), 1)  # 绘制文字
        cv2.putText(self.constant, "num=%s" % str(int(num)), (30, 60), cv2.FONT_HERSHEY_COMPLEX, 0.6,
                    (0, 191, 255), 1)  # 绘制文字


    def savefig(self, filename:str):
        cv2.imwrite(filename, self.constant)


    def run(self):
        # imgGray = cv2.adaptiveThreshold(self.img_gray,
        #                                 255,
        #                                 cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
        #                                 cv2.THRESH_BINARY, 11, 2)  # 单通道照片二值化
        imgGray = cv2.cvtColor(self.img_rgb, cv2.COLOR_RGB2GRAY)  # 转灰度图
        imgBlur = cv2.GaussianBlur(imgGray, (5, 5), 1)  # 高斯模糊
        # mean_img = cv2.pyrMeanShiftFiltering(cv2.cvtColor(imgGray, cv2.COLOR_GRAY2BGR), 20, 2)  # 色彩平滑，后面两个参数可以根据自己的效果进行调整
        # imgCanny = cv2.Canny(mean_img, 60, 60)  # Canny算子边缘检测
        imgCanny = cv2.Canny(imgBlur, 60, 60)  # Canny算子边缘检测
        self.ShapeDetection(imgCanny)  # 形状检测


if __name__ == '__main__':
    fig_name = "./img/test.jpg"
    det = Detection()
    det.read_img(fig_name)
    det.run()
    det.show_fig()
    det.savefig("./img/test_output.png")



